Skip to content

C/C++: Detect ambiguous assignment of comparison results - #22336

Open
theinfosecguy wants to merge 2 commits into
github:mainfrom
theinfosecguy:cpp-ambiguous-assignment-condition
Open

C/C++: Detect ambiguous assignment of comparison results#22336
theinfosecguy wants to merge 2 commits into
github:mainfrom
theinfosecguy:cpp-ambiguous-assignment-condition

Conversation

@theinfosecguy

@theinfosecguy theinfosecguy commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Adds cpp/ambiguous-assignment-of-comparison to flag ambiguous assignments when the assignment result is used as a truth value, such as:

if ((status = read_status() < 0))

The query distinguishes this from explicitly grouped assign-then-compare and compare-then-assign expressions. It includes C and C++ tests, query help, and query-suite integration.

Local targeted and neighboring tests pass. The motivating regression is detected, and a run against git/git produced no alerts.

Fixes #22286

@ryao ryao left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I am happy you did the work for me to get this into a PR and made what appear to be improvements, would you add an Original-patch-by: to the commit message to credit my prior work?

Also, have you run your variant against any major corpora (e.g. Linux, curl, OpenZFS) to verify the lack of FPs in production code, like I did with the original version? If it helps:

https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/scan-from-the-command-line/download-databases

not isExplicitlyGrouped(comparison) and
occursInCondition(assignment) and
// Assigning a comparison result to a Boolean is normally intentional.
not assignment.getLValue().getUnspecifiedType() instanceof BoolType and

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is normally intentional, I believe not isExplicitlyGrouped(comparison) precludes this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that? It seems like the types of the expressions and the bracketing are mostly independent concerns.

@geoffw0 geoffw0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed the code and docs from a technical perspective (I haven't looked through all the test cases yet). This looks quite promising. I've also done a mass (MRVA) run and found quite a high rate of true positive results!

Comment thread cpp/ql/src/Likely Bugs/Likely Typos/AmbiguousAssignmentOfComparison.cpp Outdated
Comment thread cpp/ql/src/Likely Bugs/Likely Typos/AmbiguousAssignmentOfComparison.ql Outdated
Comment thread cpp/ql/src/Likely Bugs/Likely Typos/AmbiguousAssignmentOfComparison.ql Outdated
Original-patch-by: Richard Yao <richard@ryao.dev>
@theinfosecguy
theinfosecguy force-pushed the cpp-ambiguous-assignment-condition branch from 7784270 to 8f0ea61 Compare August 21, 2026 07:01
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

QHelp previews:

cpp/ql/src/Likely Bugs/Likely Typos/AmbiguousAssignmentOfComparison.qhelp

Ambiguous assignment of comparison used as truth value

Assignment operators have lower precedence than comparison operators. For example, status = read_status() < 0 assigns the comparison result (zero or one) to status. This can be unintended when the programmer meant to assign the return value first and then compare it with zero.

Recommendation

Use parentheses to make the intended operation order explicit. To assign first and compare the assigned value, parenthesize the assignment. To intentionally assign the comparison result, parenthesize the comparison. An explicit cast around the comparison also makes that order clear.

Example

In the first condition, status receives either zero or one instead of the value returned by read_status. The second condition explicitly performs the assignment before the comparison.

int read_status();

int check_status() {
  int status;
  if (status = read_status() < 0) // BAD: assigns the comparison result.
    return status;

  if ((status = read_status()) < 0) // GOOD: assigns first, then compares.
    return status;

  return 0;
}

References

@geoffw0 geoffw0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice thorough tests. I've nit-picked a couple of cases but they're not important ones, and you might have more insight into them than I have, from knowing the cases that motivated this query.


I've gained a lot of confidence in this query from reviewing it - just a few small things to discuss and decide if we want to make any changes or not. 👍

@geoffw0 geoffw0 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Aug 24, 2026
@geoffw0

geoffw0 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Thank you for making the changes. The CodeQL looks good to me, as do the tests and MRVA (bulk testing) results. I think I said it before, but I'm seeing lots of true positive results in real world data. :)

I've requested a quick review of the .qhelp from the docs team, we should be able to merge soon after that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C++ documentation ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C: Implicit compare-then-assign in branch conditions should be flagged

6 participants